package eg.ci.mvn.service.core.config.rabbitmq;


import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.Binding;
import org.springframework.amqp.core.Queue;
import org.springframework.amqp.rabbit.core.RabbitAdmin;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.DependsOn;

@Slf4j
@Configuration
@ConditionalOnBean(value = RabbitAdmin.class, name = MqTestRabbitFactory.BEAN_NAME_RABBIT_ADMIN)
public class MqConfig {

    @Qualifier(MqTestRabbitFactory.BEAN_NAME_RABBIT_ADMIN)
    @Autowired
    private RabbitAdmin rabbitAdmin;

    // ================================================================================================================
    //  扇出交换器 amq.fanout(type=fanout)
    //  把所有发送到该 Exchange 的消息路由到所有与它绑定的 Queue 所以 fanout 类型是所有的交换机类型里面速度最快的
    //  注意扇出是不关心 routingKey的: broadcast.test
    //  绑定两个接收的队列: testFanout1Queue,testFanout2Queue
    // ================================================================================================================

    public static final String EXCHANGE_NAME_FANOUT = "amq.fanout";
    public static final String ROUTING_KEY_FANOUT_TEST = "test.fanout.msg";
    public static final String QUEUE_TEST_FANOUT_1 = "test.fanout.msg.1";
    public static final String QUEUE_TEST_FANOUT_2 = "test.fanout.msg.2";

    @Bean(QUEUE_TEST_FANOUT_1)
    public Queue testFanout1() {
        return createTestQueue(QUEUE_TEST_FANOUT_1);
    }

    @Bean(QUEUE_TEST_FANOUT_1 + ".bing")
    @DependsOn(QUEUE_TEST_FANOUT_1)
    public Binding testFanout1Bing() {
        return createBinding(QUEUE_TEST_FANOUT_1, EXCHANGE_NAME_FANOUT, ROUTING_KEY_FANOUT_TEST);
    }

    @Bean(QUEUE_TEST_FANOUT_2)
    public Queue testFanout2() {
        return createTestQueue(QUEUE_TEST_FANOUT_2);
    }

    @Bean(QUEUE_TEST_FANOUT_2 + ".bing")
    @DependsOn(QUEUE_TEST_FANOUT_2)
    public Binding testFanout2Bing() {
        return createBinding(QUEUE_TEST_FANOUT_2, EXCHANGE_NAME_FANOUT, ROUTING_KEY_FANOUT_TEST);
    }

    // ================================================================================================================


    // ================================================================================================================
    //  直连交换器 amq.direct(type=direct)
    //  注意扇出是不关心 routingKey的: broadcast.test
    //  绑定两个接收的队列: testFanout1Queue,testFanout2Queue
    // ================================================================================================================

    public static final String EXCHANGE_NAME_DIRECT = "amq.direct";
    public static final String ROUTING_KEY_DIRECT_TEST = "test.direct.msg";
    public static final String QUEUE_TEST_DIRECT_1 = "test.direct.msg.1";
    public static final String QUEUE_TEST_DIRECT_2 = "test.direct.msg.2";

    @Bean(QUEUE_TEST_DIRECT_1)
    public Queue testDirect1() {
        return createTestQueue(QUEUE_TEST_DIRECT_1);
    }

    @Bean(QUEUE_TEST_DIRECT_1 + ".bing")
    @DependsOn(QUEUE_TEST_DIRECT_1)
    public Binding testDirect1Bing() {
        return createBinding(QUEUE_TEST_DIRECT_1, EXCHANGE_NAME_DIRECT, ROUTING_KEY_DIRECT_TEST);
    }

    @Bean(QUEUE_TEST_DIRECT_2)
    public Queue testDirect2() {
        return createTestQueue(QUEUE_TEST_DIRECT_2);
    }

    @Bean(QUEUE_TEST_DIRECT_2 + ".bing")
    @DependsOn(QUEUE_TEST_DIRECT_2)
    public Binding testDirect2Bing() {
        return createBinding(QUEUE_TEST_DIRECT_2, EXCHANGE_NAME_DIRECT, ROUTING_KEY_DIRECT_TEST);
    }

    // ================================================================================================================


    // ================================================================================================================
    //  直连交换器 amq.direct(type=direct)
    //  注意扇出是不关心 routingKey的: broadcast.test
    //  绑定两个接收的队列: testFanout1Queue,testFanout2Queue
    // ================================================================================================================

    public static final String EXCHANGE_NAME_TOPIC = "amq.topic";
    public static final String ROUTING_KEY_TOPIC_TEST = "test.topic.msg.*";
    public static final String QUEUE_TEST_TOPIC_1 = "test.topic.msg.1";
    public static final String QUEUE_TEST_TOPIC_2 = "test.topic.msg.2";
    public static final String QUEUE_TEST_TOPIC_ALL = "test.topic.msg.all";

    @Bean(QUEUE_TEST_TOPIC_1)
    public Queue testTopic1() {
        return createTestQueue(QUEUE_TEST_TOPIC_1);
    }

    @Bean(QUEUE_TEST_TOPIC_1 + ".bing")
    @DependsOn(QUEUE_TEST_TOPIC_1)
    public Binding testTopic1Bing() {
        return createBinding(QUEUE_TEST_TOPIC_1, EXCHANGE_NAME_TOPIC, QUEUE_TEST_TOPIC_1);
    }

    @Bean(QUEUE_TEST_TOPIC_2)
    public Queue testTopic2() {
        return createTestQueue(QUEUE_TEST_TOPIC_2);
    }

    @Bean(QUEUE_TEST_TOPIC_2 + ".bing")
    @DependsOn(QUEUE_TEST_TOPIC_2)
    public Binding testTopic2Bing() {
        return createBinding(QUEUE_TEST_TOPIC_2, EXCHANGE_NAME_TOPIC, QUEUE_TEST_TOPIC_2);
    }

    @Bean(QUEUE_TEST_TOPIC_ALL)
    public Queue testTopicAll() {
        return createTestQueue(QUEUE_TEST_TOPIC_ALL);
    }

    @Bean(QUEUE_TEST_TOPIC_ALL + ".bing")
    @DependsOn(QUEUE_TEST_TOPIC_ALL)
    public Binding testTopicALLBing() {
        return createBinding(QUEUE_TEST_TOPIC_ALL, EXCHANGE_NAME_TOPIC, ROUTING_KEY_TOPIC_TEST);
    }

    // ================================================================================================================

    private Queue createTestQueue(String queueName) {
        Queue queue = new Queue(queueName, true, false, false);
        queue.setAdminsThatShouldDeclare(rabbitAdmin);
        return queue;
    }

    private Binding createBinding(String queueName, String exchangeName, String routingKey) {
        Binding binding = new Binding(queueName, Binding.DestinationType.QUEUE, exchangeName, routingKey, null);
        binding.setAdminsThatShouldDeclare(rabbitAdmin);
        return binding;
    }

}
